include('shared.lua')

CreateConVar("cl_draw_catmullrom_cameras", "1")

ENT.RenderGroup = RENDERGROUP_BOTH
local NODE_MATERIAL = Material( "sprites/light_frame_grip" )

local TRACK_MATERIAL  = Material("sprites/dacre_track")
local LINK_MAT = Material("cable/physbeam")
local SpriteOffset = Vector(0, 0, 32)

local TRACK_MATERIALB = Material("cable/white")
local MAT_HIGHLIGHT = Material("sprites/physg_glow1")

local VectorUp = Vector(1.25, 1.25, 1.25)

local CurrentHighlightIdx	= -1

ENT.KeyTextures = {}

//TODO: consider using file library to write out an RT settings text file..??

function ENT:Initialize()

	self:InitController()
	
	self.ShouldDraw     = 1
	self.ShouldDrawInfo = false
	
	self.NodeID = -1
	self.LastDrawCheckTimestamp = 0
	
	self.ZoomTimestamp = 0
	self.LastGuideBeamRenderTimestamp = 0
	
	self:FireShootOff()
	self.ViewFindMaterial = Material("models/rendertarget")//Material("system/rt")
	
	//For pathway binding to track
	self.NumPathways = 0
	self.PathwayTable = {}
end


function ENT:Think()

	self.NodeID = self.BaseClass.GetNodeIndex(self)
	self:UpdatePathwayAttachment()

	if self:GetNWInt("show_view_finder") == 1 && LocalPlayer():GetNWInt("show_objects") == 1 then

		local OldRT = render.GetRenderTarget();
		local viewFindRT = GetRenderTarget( "ViewFindRT", 512, 512, true )

		render.SetRenderTarget(viewFindRT)

		render.SetViewPort( 0, 0, 512, 512)
		render.Clear( 0, 0, 0, 0, true)

		local CamData = {} 
		CamData.angles = self:GetAngles() 
		CamData.origin = self:GetPos() + (self:GetForward() * 10)
		CamData.x = 0 
		CamData.y = 0 
		CamData.w = 512
		CamData.h = 512
		render.RenderView( CamData ) 
		render.SetRenderTarget( OldRT )
		render.SetViewPort( 0, 0, ScrW(), ScrH() )

		if viewFindRT then
		self.ViewFindMaterial:SetMaterialTexture( "$basetexture", viewFindRT)
		end
	end

	local eyeTrace = LocalPlayer():GetEyeTrace()

	if eyeTrace.Entity:IsValid() then
		if(eyeTrace.Entity == self.Entity) then
			self.IsMouseOver = true
		end
	else
		self.IsMouseOver = false
	end

	self.MouseOverIdx = -1

	if self:GetNWBool("IsMapController") then return end
	if not self:GetNWEntity("MasterController").DoZoom then return end -- Haven't received the controller yet
	

	if LocalPlayer():GetNWEntity("UnderControlCatmullRomCamera") == self:GetNWEntity("MasterController") then
		if not self.WasPlayingFOVHackz then
			self.CatmullRomController:Reset()
			
			self.WasPlayingFOVHackz = true
		end
		
		self:RemoveGuideGhost()
		
		return self:GetNWEntity("MasterController"):DoZoom()
	else
		self.WasPlayingFOVHackz = false
	end
	
	self:TrackEntity(self.Entity:GetNetworkedEntity("TrackEnt"), self.Entity:GetNetworkedVector("TrackEntLPos"))
	
	self.ShouldDrawInfo = (self:GetNWEntity("MasterController"):GetNetworkedEntity("ControllingPlayer") == LocalPlayer())
	self.ShouldDraw     = (GetConVarNumber("cl_draw_catmullrom_cameras") == 0) and 0 or 1 -- Like that you can see other player's cameras while you're filming
	
	if (self.ShouldDraw == 0) then return end
	if not self:GetNWBool("IsMasterController") then return end
	
	//self.Key = self:GetNWInt("NumPadKey")
	//
	//if not self.KeyTextures[self.Key] then
	//	self.KeyTextures[self.Key] = Material("sprites/key_" .. self.Key) -- :/
	//end
	
	self.Texture = self.KeyTextures[self.Key]
	
	self:GetPointData()
	
	if #self.CatmullRomController.PointsList >= 4 then
		self.CatmullRomController:CalcEntireSpline()
	else
		self:RemoveGuideGhost()
	end
	
	
	CurrentHighlightIdx = self.Entity:GetNWInt("MouseOverIdx")

	self:NextThink(CurTime() + .5)
end

//****************************************************
//*	Enables the client to maintain up to date awareness
//* as to the actor pathways that are currently attached 
//* to itself
function ENT:UpdatePathwayAttachment()

	local svNumPathways = self:GetNWInt("VarNumPaths")

	//If our number of pathways differs from the server
	//we know we either need to add or remove a pathway
	if svNumPathways != self.NumPathways then
	
		//Try to find out the ID of the pathway node of 
		//interest (ie could be being added or removed)
		local svPathwayEntID = self:GetNWInt("VarPathEntID")
		if (svPathwayEntID < 0) then
			self.BaseClass.PrintError(self, "(svPathwayEntID < 0)")
			return 
		end
		
		local newPathway = ents.GetByIndex(svPathwayEntID)

		if not self.BaseClass.IsPathNode(self, newPathway) then
			self.BaseClass.PrintError(self, "not self.BaseClass.IsPathNode(self, newPathway)")
			return 
		end

		self.PathwayTable = self.PathwayTable or {}
		
		if svNumPathways > self.NumPathways then
			self.PathwayTable[newPathway:EntIndex()] = newPathway
		end

		if svNumPathways < self.NumPathways then
			self.PathwayTable[newPathway:EntIndex()] = nil
		end

		self.NumPathways = svNumPathways
	end
end

function ENT:Draw()

	if self:GetNWBool("IsMapController") or LocalPlayer():GetNWInt("show_objects") == 0 then 
		return 
	end

	if self:GetNWBool("IsMasterController") then 
		self.BaseClass.DrawTrackName(self)
	end


	if not self:GetNWEntity("MasterController").RequestGuideBeamDraw then return end -- Haven't received the controller yet
	
	if self.ShouldDraw == 0 then return end
	if LocalPlayer():GetNWEntity("UnderControlCatmullRomCamera") == self:GetNWEntity("MasterController") then return end
		
	
	local wep = LocalPlayer():GetActiveWeapon()
	
	if wep:IsValid() and (wep:GetClass() == "gmod_camera") then return end
	
	self:DrawFraming()
	self:DrawNodeLinks()

	//self:DrawGuideBeam() //Draws the running camera
	self:RequestGuideBeamDraw(self.CLTrackIndex) //Draws the glowing line
	
	if self.NodeID == 1 or (self:GetNWEntity("ChildCamera"):IsValid() == false) then
		render.SetMaterial(NODE_MATERIAL)
		render.DrawSprite(self.Entity:GetPos(), 32, 32, Color(255,255,255,255))
	else
		self.Entity:DrawModel()	//Draws the camera
	end

	//self.IndexData.NodeIndex = 0
	self.BaseClass.DrawNumber(self, self.NodeID)
	//DRAW VIEW FINDER
	self:DrawViewFinder()
	
	
	if (self:GetNWBool("IsHighlighted") || self.IsMouseOver) then
		self:DrawSelected()
	end

end

function ENT:DrawTranslucent()
	if self:GetNWBool("IsMapController") then return end
	if not self:GetNWBool("IsMasterController") then return end
	
	if (not self.ShouldDrawInfo) or (not self.Texture) then return end
	if LocalPlayer():GetNWEntity("UnderControlCatmullRomCamera") == self:GetNWEntity("MasterController") then return end
	
	local wep = LocalPlayer():GetActiveWeapon()
	
	if wep:IsValid() then
		if wep:GetClass() == "gmod_camera" then return end
	end
	
	render.SetMaterial(self.Texture)
	render.DrawSprite(self.Entity:GetPos() + SpriteOffset, 16, 16, color_white)
	
	self.Entity:DrawModel()
end

function ENT:DoZoom()
	local CTime = CurTime()
	
	if self.ZoomTimestamp < CTime then
		self.ZoomTimestamp = CTime
		
		self.CatmullRomController:CalcPerc() -- Can't be done in the parameter call or a side effect doesn't manifest properly
		LocalPlayer().CatmullRomCamsTrackZoom = self.CatmullRomController:CalcZoom()
	end
end

local scrn = 1
local size = 2 * scrn
local TRACK_MATERIAL  = Material("sprites/dacre_track")
local LINK_MATERIAL  = Material("sprites/dacre_link")
local FRAME_MATERIAL = nil
//****************************************************
//* This function renders the currently selected 'frame'
//* as requested by the user. This overlays the screen
function ENT:DrawFraming()

	if self.BaseClass.GetNodeIndex(self) == 1 then
		local frame = self:GetNWString("framing_type")
		
		if frame == "nil" or frame == "" or frame == nil then
			FRAME_MATERIAL = nil
		else
			FRAME_MATERIAL = Material( "myproject/frames/" .. frame )
		end
	end

end

function clientFrame()
	
	if FRAME_MATERIAL != nil then
		render.SetMaterial(FRAME_MATERIAL)
		render.DrawScreenQuad()
	end
end
hook.Add("HUDPaint", "clientFrame", clientFrame)  

//****************************************************
//* This function renders any links that need to be drawn 
//* from/to this node from other pathways or nodes in the scene
function ENT:DrawNodeLinks()
	local CTime = CurTime()

	//Look to see if we are in the middle of a user
	//constructing a link from myself to an actor or
	//node. Render this line to provide visual feedback
	local constructDraw, constructEndpoint = self.BaseClass.GetConstructPoint(self)
	if constructDraw == true then
		render.SetMaterial(LINK_MATERIAL)

		render.StartBeam(2)
		render.AddBeam(self:GetPos(), 5, 0, self.Color)
		render.AddBeam(constructEndpoint, 5, 1, self.Color)
		render.EndBeam()

	end

	//Look to see if there are any links existing between myself
	//and other pathways and draw them accordingly
	if self.PathwayTable then 
		render.SetMaterial(LINK_MATERIAL)
		for k, v in pairs(self.PathwayTable) do
			if self.BaseClass.IsValid(self, v) then
				render.StartBeam(2)
				render.AddBeam(self:GetPos(), 5, 0, self.Color)
				render.AddBeam(v:GetPos(), 5, 1, self.Color)
				render.EndBeam()

			end
		end
	end

end

function ENT:DrawSelected()

	render.SetMaterial(MAT_HIGHLIGHT)
	render.DrawSprite(self:GetPos(),64,64,Color(255,255,255,255))
end


function ENT:DrawViewFinder()

	if self:GetNWInt("show_view_finder") == 1 then
		local pos = self:GetPos() + (self:GetRight() * 1.75) + (self:GetForward() * -3.5) + (self:GetUp() * 15)
		local ang = self:GetAngles()
		ang:RotateAroundAxis(ang:Right(), -90)
		ang:RotateAroundAxis(ang:Up(),     90)
		ang:RotateAroundAxis(ang:Right(),  90)
		
		local viewFindData = {}
		viewFindData.origin = self:GetPos()
		viewFindData.angles = self:GetAngles()


		cam.Start3D2D(pos, ang, 1)
		render.SetMaterial(Material( "sprites/dacre_black" ))
		render.DrawQuadEasy(Vector(15,0,0),Vector(1,0,0),67,67,Color(255,255,255,255),270.0)

		render.SetMaterial(self.ViewFindMaterial)
		render.DrawQuadEasy(Vector(15,0,0),Vector(1,0,0),60,60,Color(255,255,255,255),270.0)
		
		cam.End3D2D()
	end
end


function ENT:FireShootOff()
	if not (self and self:IsValid()) then return end
	
	self.CurShootOffStart = SysTime()
	self.CurShootOff      = self.CurShootOffStart + .75
	--[[
	if math.random(1, 2) == 1 then
		self.CurShootOffRoll = (math.random(1, 2) == 1) and math.random() or math.random() * -1
	else
		self.CurShootOffRoll = 0
	end
	--]]
end

function ENT:DrawGuideBeam()
	if self:GetNWBool("IsMapController") then return end
	
	if not self:GetNWBool("IsMasterController") then
		if self:GetNWEntity("MasterController"):IsValid() and (LocalPlayer():GetNWEntity("UnderControlCatmullRomCamera") ~= self:GetNWEntity("MasterController")) then
			return self:GetNWEntity("MasterController"):DrawGuideBeam()
		end
		
		return
	end
	
	if #self.CatmullRomController.PointsList < 4 then
		self:RemoveGuideGhost()
		
		return --print("not enough points.", #self.CatmullRomController.PointsList)
	end
	

	if self:GetNWBool("DoHighlight") then
	self:DrawSelected()
	end

	local CTime = UnPredictedCurTime()
	
	if self.LastDrawCheckTimestamp > CTime then return end--print("too soon") end
	
	self.LastDrawCheckTimestamp = CTime
	
	local size = 35 + math.abs(self.CatmullRomController.Perc - .5) * 100
	
	local pos, ang = self:GetGuideCamPosAng()
	
	if not self.GuideCameraGhost then
		self.GuideCameraGhost = ClientsideModel(CAMERA_MODEL, RENDERGROUP_OPAQUE)
	end
	
	self.GuideCameraGhost:SetModelScale(VectorUp * (math.sin(1 - math.abs(self.CatmullRomController.Perc - .5)) * .5 + .6))
	
	self.GuideCameraGhost:SetAngles(ang)
	self.GuideCameraGhost:SetPos(pos)
end

function ENT:RequestGuideBeamDraw(trackindex)
	if not trackindex then return end
	if (not self:GetNWBool("IsMasterController")) then
		if self:GetNWEntity("MasterController").RequestGuideBeamDraw then
			return self:GetNWEntity("MasterController"):RequestGuideBeamDraw(trackindex)
		end
		
		return
	end
	
	if (trackindex == 1) or (trackindex == self.CatmullRomController.CLEntityListCount) or (self.CatmullRomController.CLEntityListCount == 0) then 
		return end
	
	local CTime = CurTime()
	
	local drawbackbeam    = (trackindex > 2) and self.CatmullRomController.EntityList[trackindex - 1] and (self.CatmullRomController.EntityList[trackindex - 1].LastGuideBeamRenderTimestamp < CurTime())
	local drawforwardbeam = (trackindex < self.CatmullRomController.CLEntityListCount - 1) and self.CatmullRomController.EntityList[trackindex] and (self.CatmullRomController.EntityList[trackindex].LastGuideBeamRenderTimestamp < CurTime())
	
	render.SetMaterial(TRACK_MATERIAL)

	if drawbackbeam then
		self.CatmullRomController.EntityList[trackindex - 1].LastGuideBeamRenderTimestamp = CTime
		render.StartBeam(self.CatmullRomController.STEPS + 2)
			ok, err = pcall(self.RenderSubBeams, self, CTime, (trackindex - 1))
		render.EndBeam()
	end
	
	if drawforwardbeam then
		self.CatmullRomController.EntityList[trackindex].LastGuideBeamRenderTimestamp = CTime
		render.StartBeam(self.CatmullRomController.STEPS + 2)
			ok, err = pcall(self.RenderSubBeams, self, CTime , trackindex)
		render.EndBeam()
	end
end

function ENT:GetGuideCamPosAng(pos1, pos2, pos3, pos4)
	if self:GetNWBool("IsMasterController") then
		self:CalcPerc() -- Can't be done in the parameter call or a side effect doesn't manifest properly
		
		return self.CatmullRomController:Point(), self.CatmullRomController:Angle()
	end
end

function ENT:RenderBeams()
	local CTime = CurTime()
	render.AddBeam(self.CatmullRomController.PointsList[2], 10, CTime, color_white)

	for i = 1, #self.CatmullRomController.Spline do
		render.AddBeam(self.CatmullRomController.Spline[i], 10, CTime, color_white)
	end
end

function ENT:RenderSubBeams(CTime, trackindex)
	local base = (trackindex - 2) * self.CatmullRomController.STEPS	

	render.AddBeam(self.CatmullRomController.PointsList[trackindex], 10, 0 - CTime or 1, beamColor)
	for i = 1, self.CatmullRomController.STEPS do
		render.AddBeam(self.CatmullRomController.Spline[base + i], 10, i - CTime or 1, beamColor)
	end
	
	render.AddBeam(self.CatmullRomController.PointsList[trackindex + 1], 10, CTime or 1, beamColor)
end

function ENT:RemoveGuideGhost()
	if self.GuideCameraGhost and self.GuideCameraGhost:IsValid() then
		self.GuideCameraGhost:Remove()
		
		self.GuideCameraGhost = nil
	end
	
	--return collectgarbage()
end

function ENT:Lock()
	self.IsLocked = true
end

function ENT:Unlock()
	self.IsLocked = false
end
